package scheduler

import "learngo/crawler/engine"

type QueuedScheduler struct {
	//对原来gorutine做的request,换成一个队列，队列数据从这个chan去拿
	requestChan chan engine.Request
	//chan engine.Request 100个chan，都放在workerChan chan下
	workerChan chan chan engine.Request
}

func (s *QueuedScheduler) WorkerChan() chan engine.Request {
	return make(chan engine.Request)
}

func (s *QueuedScheduler) Submit(r engine.Request) {
	//初始化会先放一个Request进request chan，后面循环这个方法不断放入
	s.requestChan <- r
}

func (s *QueuedScheduler) WorkerReady (w chan engine.Request){
	s.workerChan <- w
}

//多协程，先将Request chan拉拉一个Reuqest出来（<- s.requestChan），
//然后放入一个Request队列var requestQ  []engine.Request
//接着将s.workerChan拉一个Reuqest chan出来（<- s.workerChan）
//然后放入一个workerQ队列var workerQ []chan engine.Request
//取出队列requestQ中的第一个即Request。取出workerQ队列中的第一个即Request chan
//将Request放入Request chan，这是最终目的
//这样做，保证chan有足够的时间去处理Request，并且处理完当前Request后，接着处理下一个
//如果不这样做的话，当消耗完处理request的chan后（10个）, 这是时候再有request过来的时候
//因为chan还在处理request，而导致无法处理后面到来的request，而导致挂起

//改变了QueuedScheduler内部数据，因此要改成指针接收者
func (s *QueuedScheduler) Run() {
	//每个worker都有自己的Request chan, 这里再创建一个chan, 这个chan
	//包含了所有的Request chan
	s.workerChan = make(chan chan engine.Request)
	s.requestChan = make(chan engine.Request)
	go func() {
		var requestQ  []engine.Request
		var workerQ []chan engine.Request
		for {
			//activeRequest最终会送入activeWorker， activeWorker <- activeRequest
			//最终目的 activeWorker <- activeRequest
			var activeRequest engine.Request
			var activeWorker chan engine.Request
			if len(requestQ)>0 && len(workerQ)>0{
				//从队列中取出一个request，
				activeRequest = requestQ[0]
				//从队列中取出一个worker chan
				activeWorker = workerQ[0]
			}
			select {
				case r := <- s.requestChan:
					requestQ = append(requestQ, r)
				case w := <- s.workerChan:
					workerQ = append(workerQ, w)
				case activeWorker <- activeRequest:
					workerQ = workerQ[1:]
					requestQ = requestQ[1:]
			}
		}
	}()
}





